home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Indent project / Indent Source / Indent_Interface.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-25  |  50.3 KB  |  1,951 lines  |  [TEXT/KEEN]

  1. /* Indent_Interface.c : Indent dialog interface */
  2. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  3.  *         This file is part of GAWK, the GNU implementation of the
  4.  * AWK Progamming Language, modified for the Macintosh (also called Indent).
  5.  *         GAWK is free software; you can redistribute or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 1, or any later version.
  8.  *         GAWK is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11.  * GNU General Public License for more details.
  12.  *         You should have received a copy of the GNU General Public License
  13.  * along with GAWK; see the file "COPYING Indent". If not, write to
  14.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  16.  */
  17.  
  18. /* Code to synthesize a command line based on user's choices in the
  19. main Indent dialog, or pass a supplied command line after some
  20. substitution.
  21.  
  22. Profile options: choose from a list of all Indent profiles in the
  23. folder "Indent profiles", or some other profile via a standard SFGetFile dialog.
  24.  
  25. Indent input options:
  26. - Specific input file; the one "fixed" option, allows user to pick one particular
  27.     input file as input
  28. - Selected front text / All of front text; takes as input all or the selected part
  29.     of the text window that happens to be in front when Indent is called
  30. - MFS selected files; takes as input all files selected for multi-file operation
  31.     in the calling application - usually multi-file searching.
  32.  
  33. Indent output options:
  34. "\pBack up and overwrite": if MFS or one specific file
  35. "\pRename with number"     : one specific file only
  36. "\pTo $tempStdOut"         : if one specific file or stdin
  37.  
  38. An "About" button displays copysquawk about Indent.
  39.  
  40. Calling program may pass in a command line - if present, skip the
  41. Indent dialog, make argv's and go straight to AWKmain().
  42. */
  43.  
  44. #include <stdlib.h>
  45. #include <stdio.h>
  46. //#include <fcntl.h>
  47. #include <string.h>
  48. #include <setjmp.h>
  49. #include "CodeResHelper.h" /* TMalloc etc */
  50. #include "CodeResource.h"
  51. #include "AppCodeComm.h"
  52.  
  53. // Some key constants
  54. #define        ETX                '\003'        /* enter                 */
  55. #define        BS                '\b'        /* backspace            */
  56. #define        HT                '\t'        /* tab                    */
  57. #define        CR                0x0D        /* return                */
  58. #define        ESC                '\033'        /* clear                */
  59. #define        FS                '\034'        /* left arrow            */
  60. #define        GS                '\035'        /* right arrow            */
  61. #define        RS                '\036'        /* up arrow                */
  62. #define        US                '\037'        /* down arrow            */
  63. #define        COMMA            ','         /* or 0x2C */
  64. #define        BLANK            ' '         /* a space */
  65. #define        OPTBL            ' '            /* option-space */
  66.  
  67. // And some macros for character handling
  68. #define alpha(c)    (('a'<=(c)&&(c)<='z')||('A'<=(c)&&(c)<='Z')||(c)=='_')
  69. #define num(c)        ('0'<=(c) && (c)<='9')
  70. #define alphanum(c)    (alpha(c)||num(c))
  71. #define white(c)    ((c) == BLANK || ((c) > 0 && (c) <= CR) || (c) == OPTBL)
  72.  
  73.  
  74. // Use better memory routines for allocating argv[]
  75. #define malloc(x) Fmalloc(x)
  76. #define realloc(x, y) Frealloc(x, y)
  77. #define free(x) Ffree(x)
  78.  
  79. extern void *alloca(unsigned short size);
  80. extern void DumpZoneList(void);
  81.  
  82. /* buffer holding position of long jump */
  83. jmp_buf        envBuf;
  84.  
  85. static short argc;
  86. static char **argv;
  87. static short NUMARGVS = 500; /* Was a #define, now variable */
  88.  
  89. short gInputError; /* Not used yet */
  90.  
  91. /* Struct recording user choices */
  92. typedef struct IndentSetup
  93.     {
  94.     short        profileMenuNum;    // profile item gnu, k&r, orig, other
  95.     short        inputType;        // input file or "metafile" specification
  96.     short        outputType;        // replace, keep backup, to stdout etc
  97.     Boolean        showOut;         // passed back to calling application
  98.     char         *profileName;    // the Indent profile
  99.     char        *inputName;     // optional, if one specific file selected
  100.     char        *outputName;    // optional, if -o option set
  101.     short        profileVRefNum; // for currently selected profile
  102.     short        defaultVRefNum; // for the folder "Indent programs"
  103.     short        otherVRefNum;     // for "unlisted" profile
  104.     } IndentSetup;
  105. /* global record of user choices */
  106. IndentSetup gIndentSetup;
  107.  
  108. // For command line passed by user in text form.
  109. typedef enum CommandLineTypesEnum
  110.     {
  111.     kErrorGetting_Arg = -1,
  112.     kNoMore_Arg = 0,
  113.     kIndentName_Arg = 1,
  114.     kStandardProfileNameArg = 2,
  115.     kProfileName_Arg = 3,
  116.     kFileName_Arg = 4,
  117.     kMFS_Arg = 5,
  118.     kStandardOutputArg = 6,
  119.     kOutputFileNameFollowsArg = 7
  120.     } CommandLineTypesEnum;
  121.  
  122. /* Dialog to set up a Indent run.
  123. */
  124. #define    IndentDlogID        410
  125. /* OK is 1, Cancel is 2 */
  126. #define AboutIndent        3
  127. #define ProgramStat        5
  128. #define InputStat        6
  129. #define OutputStat        7
  130. #define ProfilePopup    8
  131. #define InputPopup        9
  132. #define OutputPopup        10
  133. #define RunUserItem        11
  134.  
  135. /* popups */
  136. #define MainProfileID    187
  137. #define InputID            188
  138. #define OutputID        189
  139.  
  140. /* The "Take input from:" popup varies accoring to which extensions
  141. are supplied by the application: GetFrontText_Ext is nonnull only if
  142. it is appropriate to take input from a front text window - note this
  143. will be null even if the application supports the extension, in the case
  144. where no text file is open at the time this code resource is called.
  145. GetNextFileToSearch_Ext is nonnull if the application supports selecting
  146. multiple files somehow, the most common use being for multi-file
  147. searching. Again this will be passed in as NULL if there are no files
  148. selected at the time of the call.
  149. */
  150. typedef struct InputPopupItems
  151.     {
  152.     short    frontSelected,    // user's selected text in front text window
  153.             frontAll,        // all of text in front window
  154.             multiSelected,    // multiple files, as specified within application
  155.             specificFile;    // pick one with SFGetFIle
  156.     } InputPopupItems, *InPopItemPtr;
  157. static InputPopupItems    inPop;
  158.  
  159. typedef struct OutputPopupItems
  160.     {
  161.     short    replaceWithBackup,
  162.             renameWithNumber,
  163.             toStandardOut;
  164.     } OutputPopupItems, *OutPopItemPtr;
  165. static OutputPopupItems        outPop;
  166.  
  167. /* from indent.c */
  168. extern void Indent_main(short argc, char **argv);
  169.  
  170. /* Functions defined in this file: */
  171. short InvokeIndent(void); /* the external call - see Code_Main.c */
  172. void DoExiting(void);
  173. static pascal void EmptyExitToShell(void);
  174. void CleanUpAfterIndent(void);
  175. /* "command line" creation: */
  176. Boolean GetCommandLineArguments(void);
  177. Ptr FullPathNameForProfile
  178.     (Ptr        argPtr,
  179.     short        argLength,
  180.     short        *vRefNumP
  181.     );
  182. short GetWorkingDirectory
  183.     (char    *curvolName,
  184.     long    theDirID
  185.     );
  186. void InitIndentFromProfile(Ptr profileNamePtr);
  187. short GetNextCommandLineArg
  188.     (Ptr        *argPtrP,
  189.     short        *argLengthP
  190.     );
  191. /* Dialog management */
  192. Boolean DoIndentDialog(void);
  193. void CreateIndentProgramResourcePopups(void);
  194. void MaintainOutputPopup(void);
  195. void CreateProfilePopup(void);
  196. long FindIndentProfileFolder(char *curvolName, char *folderName);
  197. void AddProfilesToMenu(char *curvolName, long theDirID, MenuHandle theMenu);
  198. void AlphaAppendMenu(MenuHandle theMenu, short lowPoint, char *name);
  199. short AlphaMenuPos(char *name, MenuHandle theMenu, short highPoint, short lowPoint);
  200. short MenuCompare(char *name, MenuHandle theMenu, short index);
  201. short PtrLenPascalCompare(Ptr spatPtr, short patLen, Ptr stargetPtr);
  202. pascal void IndentPopProc(WindowPtr wdPtr, short item);
  203. pascal void ButtonProc(WindowPtr wdPtr, short item);
  204. void ResetIndentSetup(DialogPtr dPtr);
  205. void SetPopupMark(short theMenuID, short newItem);
  206. void GetIndentProfileName(DialogPtr dPtr, short item);
  207. void GetInputFileName(void);
  208. void DestroyIndentPopups(void);
  209. Boolean GetCommandLineFromDlogResult(void);
  210. char *CreateStdIn(Boolean wholeFile);
  211. Boolean GetInputsFromMFS(void);
  212. char *GetRenumberedName(char *oldName);
  213. Boolean IncrementName(StringPtr copyOfName);
  214. void RedrawItem(DialogPtr dPtr, short itemHit);
  215. void RedrawDialog(DialogPtr dPtr);
  216. void JumpOnIndentError(short inputErrorNumber);
  217. void HandleIndentError(void);
  218.  
  219. /* Memory init, get command line either as passed directly or from dialog,
  220. set watch cursor, call Indent_main, clean up, return result code.
  221. */
  222. short InvokeIndent(void)
  223.     {
  224.     
  225.     InitTempCodeMemory(); /* see CodeResource_Helper.c */
  226.     
  227.     // Rev May 96, see if caller passed along a command line. If there is any failure
  228.     // or just no command line, do the dialog.
  229.     if (!GetCommandLineArguments())
  230.         {
  231.         //OKStopAlert("DBG could not get cmd line arguments");
  232.         if (argv != NULL)
  233.             {
  234.             while (--argc >= 0)
  235.                 {
  236.                 if (argv[argc] != NULL)
  237.                     free(argv[argc]);
  238.                 }
  239.             free(argv);
  240.             }
  241.         argv = NULL;
  242.         argc = 0;
  243.         if (!DoIndentDialog())
  244.             {
  245.             DoExiting();
  246.             return(-1); /* user cancelled, most likely, or out of memory */
  247.             }
  248.         }
  249.     SetWatchCursor();
  250.     
  251.     /* If Indent fails, it long-jumps back to here
  252.     and setjmp returns non-zero. */
  253.     
  254.     if (!setjmp(envBuf))
  255.         {
  256.         //OKStopAlert("DBG about to call Indent_main");
  257.         Indent_main(argc, argv);
  258.         CleanUpAfterIndent();
  259.         //_exiting(1);
  260.         /* show result if wanted */
  261.         DoExiting();
  262.         if (gIndentSetup.showOut)
  263.             {
  264.             return(1);
  265.             }
  266.         return(0);
  267.         }
  268.     else
  269.         {
  270.         CleanUpAfterIndent();
  271.         //_exiting(1);
  272.         HandleIndentError();
  273.         DoExiting();
  274.         if (gInputError)
  275.             return(-2);
  276.         else
  277.             return(1);
  278.         }
  279.     }
  280.  
  281. enum
  282.     {
  283.     uppExitToShellProcInfo = kPascalStackBased
  284.     };
  285. // Patch ExitToShell out temporarily and call exit()
  286. void DoExiting(void)
  287.     {
  288.     pascal void (*gOldExitToShell)(void);
  289.     UniversalProcPtr EmptyExitToShellProcPtr;
  290.     
  291.     gOldExitToShell = (void *)GetToolTrapAddress(0xA9F4);
  292.     EmptyExitToShellProcPtr = NewRoutineDescriptor((ProcPtr)&EmptyExitToShell,
  293.                                     uppExitToShellProcInfo,
  294.                                     GetCurrentISA());
  295.     SetToolTrapAddress(EmptyExitToShellProcPtr, 0xA9F4);
  296.     exit(0);
  297.     SetToolTrapAddress((UniversalProcPtr)gOldExitToShell, 0xA9F4);
  298.     }
  299.  
  300. static pascal void EmptyExitToShell(void)
  301.     {
  302.     ;
  303.     }
  304.  
  305. void CleanUpAfterIndent(void)
  306.     {
  307.     /* Call TFreeAll if using TMalloc etc, call FFreeAll if using Fmalloc etc
  308.     -at present, using Fmalloc which is better on all scores. */
  309.     
  310.     FFreeAll();
  311.     //alloca(0); not needed
  312.     }
  313.  
  314. /*
  315. Under version 4, caller may pass along a command line in text form. If so,
  316. parse it into argv. Return TRUE if got a good command line, FALSE otherwise.
  317. Memory allocation is done here, advancing through the text of the command line is
  318. done by GetNextCommandLineArg().
  319. For program names, use Indent program folder if no path specified.
  320. For input, "MFS" means multi-file selection (if allowed), case-sensitive there.
  321. */
  322. Boolean GetCommandLineArguments(void)
  323.     {
  324.     Ptr            argPtr = NULL;
  325.     short        argLength = 0;
  326.     Ptr            tempPtr;
  327.     Ptr            profileNamePtr = NULL;
  328.     long        len;
  329.     short        i;
  330.     short        argumentType;
  331.     short        vRefNum = 0;
  332.     short        programArgument = 0;
  333.     Boolean        gotCommandLine = FALSE;
  334.     
  335.     // init IndentSetup.
  336.     gIndentSetup.showOut = FALSE;
  337.     gIndentSetup.profileName = gIndentSetup.inputName = NULL;
  338.     gIndentSetup.outputName = NULL;
  339.     
  340.     argc = 0;
  341.     
  342.     if (    gacc.extend2ID == 'VER4'
  343.         &&     gacc.commandLine != NULL )
  344.         {
  345.         gotCommandLine = TRUE;
  346.         argv = (char **)malloc( sizeof(char *) * NUMARGVS );
  347.         if (argv == NULL)
  348.             {
  349.             OKStopAlert("Could not allocate argv array, ouch!");
  350.             return(FALSE);
  351.             }
  352.         while ( (argumentType = GetNextCommandLineArg(&argPtr, &argLength)) > 0)
  353.             {
  354.             switch (argumentType)
  355.                 {
  356.             case kIndentName_Arg:
  357.                 //OKStopAlert("DBG about to allocate code name");
  358.                 // hawk name always as first arg
  359.                 len = strlen(gacc.thisCodeName);
  360.                 argv[argc] = (Ptr)malloc(len+1);
  361.                 if (!argv[argc])
  362.                     {
  363.                     OKStopAlert("Could not allocate Indent name, ouch!");
  364.                     return(FALSE);
  365.                     }
  366.                 BlockMove(gacc.thisCodeName, argv[argc], len+1);
  367.                 ++argc;
  368.             break;
  369.             case kProfileName_Arg:
  370.                 //OKStopAlert("DBG about to allocate program name");
  371.                 profileNamePtr = FullPathNameForProfile(argPtr, argLength, &vRefNum);
  372.                 if (profileNamePtr == NULL)
  373.                     {
  374.                     OKStopAlert("Could not allocate profile name, ouch!");
  375.                     return FALSE;
  376.                     }
  377.             break;
  378.             case kOutputFileNameFollowsArg:
  379.                 //OKStopAlert("DBG about to allocate dash oh");
  380.                 tempPtr = (Ptr)malloc(3);
  381.                 if (tempPtr == NULL)
  382.                     {
  383.                     OKStopAlert("Could not allocate -o separator, ouch!");
  384.                     return FALSE;
  385.                     }
  386.                 BlockMove("-o", tempPtr, 3);
  387.                 argv[argc] = tempPtr;
  388.                 ++argc;
  389.             break;
  390.             case kStandardOutputArg:
  391.                 //OKStopAlert("DBG about to allocate dash st");
  392.                 tempPtr = (Ptr)malloc(4);
  393.                 if (tempPtr == NULL)
  394.                     {
  395.                     OKStopAlert("Could not allocate -st, ouch!");
  396.                     return FALSE;
  397.                     }
  398.                 BlockMove("-st", tempPtr, 4);
  399.                 argv[argc] = tempPtr;
  400.                 ++argc;
  401.             break;
  402.             case kFileName_Arg:
  403.             case kStandardProfileNameArg:
  404.                 //OKStopAlert("DBG about to allocate one input or output file");
  405.                 tempPtr = (Ptr)malloc(argLength + 1);
  406.                 if (tempPtr == NULL)
  407.                     {
  408.                     OKStopAlert("Could not allocate input file name, ouch!");
  409.                     return FALSE;
  410.                     }
  411.                 BlockMove(argPtr, tempPtr, argLength);
  412.                 tempPtr[argLength] = '\0';
  413.                 argv[argc] = tempPtr;
  414.                 ++argc;
  415.             break;
  416.             case kMFS_Arg:
  417.                 //OKStopAlert("DBG about to allocate all MFS files");
  418.                 if (!GetInputsFromMFS())
  419.                     {
  420.                     OKStopAlert("Could not get MFS file names, ouch!");
  421.                     return FALSE;
  422.                     }
  423.             break;
  424.             default:
  425.                 // unknown argument type
  426.             break;
  427.                 } // switch
  428.             } // while
  429.         
  430.         if (argc < 2)
  431.             {
  432.             OKStopAlert("\"Indent\" was followed by insufficient information to run!");
  433.             return FALSE;
  434.             }
  435.         else
  436.             {
  437.             // Load profile if one was mentioned
  438.             if (profileNamePtr != NULL)
  439.                 {
  440.                 InitIndentFromProfile(profileNamePtr);
  441.                 }
  442.             }
  443.         
  444.         // Tack on "-npro" to suppress reading default profile
  445.         tempPtr = (Ptr)malloc(6);
  446.         if (tempPtr == NULL)
  447.             {
  448.             OKStopAlert("Could not allocate -npro, ouch!");
  449.             return FALSE;
  450.             }
  451.         BlockMove("-npro", tempPtr, 6);
  452.         argv[argc] = tempPtr;
  453.         ++argc;
  454.         } // if v4 with cmd line
  455.     
  456.     return gotCommandLine;
  457.     }
  458.  
  459. /* If we don't already have a full path, use the Indent profile folder
  460. to make one. */
  461. Ptr FullPathNameForProfile
  462.     (Ptr        argPtr,
  463.     short        argLength,
  464.     short        *vRefNumP
  465.     )
  466.     {
  467.     char        curvolName[32];
  468.     char        pProgName[64];
  469.     long        theDirID = 0;
  470.     short        vRefNum = *vRefNumP;
  471.     Ptr            tempPtr = NULL;
  472.     long        len;
  473.     Ptr            cPtr;
  474.     Ptr            endPtr;
  475.     
  476.     // Does the program name contain a colon?
  477.     cPtr = argPtr;
  478.     endPtr = cPtr + argLength;
  479.     for (; cPtr < endPtr; ++cPtr)
  480.         {
  481.         if (*cPtr == ':')
  482.             break;
  483.         }
  484.     // No colon means we have to make the full path name
  485.     if (cPtr >= endPtr)
  486.         {
  487.         if (argLength > 63)
  488.             argLength = 63;
  489.         BlockMove(argPtr, pProgName + 1, argLength);
  490.         pProgName[0] = argLength;
  491.         if ( vRefNum != 0
  492.           || (theDirID = FindIndentProfileFolder(curvolName, (char *)"\pIndent profiles")) != 0 )
  493.             {
  494.             if (theDirID != 0)
  495.                 {
  496.                 vRefNum = GetWorkingDirectory(curvolName, theDirID);
  497.                 *vRefNumP = vRefNum;
  498.                 }
  499.             tempPtr = (Ptr)malloc(256);
  500.             if (tempPtr != NULL)
  501.                 {
  502.                 AppendPStr((Byte *)(FullPathNameFromVRefNum(vRefNum,(Byte *)(tempPtr))),
  503.                     (Byte *)(pProgName));
  504.                 PtoCstr((StringPtr)tempPtr);
  505.                 }
  506.             }
  507.         }
  508.     // If it has a colon, just tack '-f' in front of a copy.
  509.     else
  510.         {
  511.         tempPtr = (Ptr)malloc(argLength + 1);
  512.         if (tempPtr != NULL)
  513.             {
  514.             BlockMove(argPtr, tempPtr, argLength);
  515.             tempPtr[argLength] = '\0';
  516.             }
  517.         }
  518.     return tempPtr;
  519.     }
  520.  
  521. short GetWorkingDirectory
  522.     (char    *curvolName,
  523.     long    theDirID
  524.     )
  525.     {
  526.     WDPBRec            theParms;
  527.     HVolumeParam    vParms;
  528.     char            volName[32];
  529.     short            theVolRef, vRefNum;
  530.     
  531.     /* Some shenanigans to open working directory for code resources */
  532.     BlockMove(curvolName, volName, 32);
  533.     vParms.ioCompletion = NULL;
  534.     vParms.ioNamePtr = (StringPtr)(volName);
  535.     vParms.ioVRefNum = -32768;
  536.     vParms.ioVolIndex = -1;
  537.     if (PBHGetVInfo((HParmBlkPtr)&vParms, FALSE))
  538.         theVolRef = 0;
  539.     else
  540.         theVolRef = vParms.ioVRefNum;
  541.     theParms.ioCompletion = NULL;
  542.     theParms.ioVRefNum = theVolRef;
  543.     theParms.ioNamePtr = NULL;
  544.     theParms.ioWDDirID = theDirID;
  545.     theParms.ioWDProcID = 'ERIK';
  546.     if (PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  547.         vRefNum = 0;
  548.     else
  549.         vRefNum = theParms.ioVRefNum;
  550.     
  551.     theParms.ioNamePtr = NULL;
  552.     theParms.ioVRefNum = vRefNum;
  553.     theParms.ioWDIndex = 0;
  554.     theParms.ioWDProcID = 0;
  555.     if (PBGetWDInfo(&theParms,false))
  556.         vRefNum = 0;
  557.     return vRefNum;
  558.     }
  559.  
  560. /* Grab contents of file profileNamePtr, load them into indent variables.
  561. */
  562. void InitIndentFromProfile(Ptr profileNamePtr)
  563.     {
  564.     extern void initialize_backups(void);
  565.     extern void set_defaults(void);
  566.     extern char *set_profile (char *customFileName);
  567.     
  568.     initialize_backups();
  569.     set_defaults();
  570.     set_profile(profileNamePtr);
  571.     }
  572.  
  573. /* Grab the next command line argument, determine its type, or return 0.
  574. Being nice, we strip out quotes here.
  575. Pass *argPtrP = NULL the first time.
  576. kErrorGetting_Arg = -1,
  577. kNoMore_Arg = 0,
  578. kIndentName_Arg = 1,
  579. kStandardProfileNameArg = 2,
  580. kProfileName_Arg = 3,
  581. kFileName_Arg = 4,
  582. kMFS_Arg = 5,
  583. kStandardOutputArg = 6,
  584. kOutputFileNameFollowsArg = 7
  585. */
  586. short GetNextCommandLineArg
  587.     (Ptr        *argPtrP,
  588.     short        *argLengthP
  589.     )
  590.     {
  591.     Ptr            argPtr = *argPtrP;
  592.     Ptr            endPtr;
  593.     short        argLength = *argLengthP;
  594.     short        argumentType = kNoMore_Arg;
  595.     long        commandLineLength;            // needed when stripping quotes
  596.     long        amountToMove;                // ditto
  597.     Boolean        stripQuotes = FALSE;
  598.     
  599.     if (argPtr == NULL)
  600.         {
  601.         argPtr = gacc.commandLine;
  602.         argumentType = kIndentName_Arg;
  603.         }
  604.     else
  605.         argPtr += argLength;
  606.     argLength = 0;
  607.     
  608.     // skip past last arg's quote
  609.     while (*argPtr == '"')
  610.         ++argPtr;
  611.     // skip white space
  612.     while (white(*argPtr))
  613.         ++argPtr;
  614.     // First arg is "Indent"
  615.     if (argumentType == kIndentName_Arg)
  616.         {
  617.         endPtr = argPtr;
  618.         while (*endPtr && !white(*endPtr))
  619.             ++endPtr;
  620.         }
  621.     // Options indicate source program, variable, input follows
  622.     else if (*argPtr == '-')
  623.         {
  624.         ++argPtr;
  625.         endPtr = argPtr;
  626.         while (*endPtr && !white(*endPtr))
  627.             ++endPtr;
  628.         // -, -o, -st, -MFS, -gnu, -kr, -orig
  629.         if (endPtr == argPtr)
  630.             argumentType = kErrorGetting_Arg;
  631.         else if (endPtr - argPtr == 1)
  632.             {
  633.             if (*argPtr == 'o')
  634.                 argumentType = kOutputFileNameFollowsArg;
  635.             }
  636.         else if (endPtr - argPtr == 2)
  637.             {
  638.             if (*argPtr == 's' && *(argPtr+1) == 't')
  639.                 argumentType = kStandardOutputArg;
  640.             else if (*argPtr == 'k' && *(argPtr+1) == 'r')
  641.                 argumentType = kStandardProfileNameArg;
  642.             }
  643.         else if (endPtr - argPtr == 3)
  644.             {
  645.             if ( *argPtr == 'M' && *(argPtr+1) == 'F'
  646.               && *(argPtr+2) == 'S' )
  647.                 argumentType = kMFS_Arg;
  648.             else if ( *argPtr == 'g' && *(argPtr+1) == 'n'
  649.               && *(argPtr+2) == 'u' )
  650.                 argumentType = kStandardProfileNameArg;
  651.             }
  652.         else if (endPtr - argPtr == 4)
  653.             {
  654.             if ( *argPtr == 'o' && *(argPtr+1) == 'r'
  655.               && *(argPtr+2) == 'i' && *(argPtr+3) == 'g' )
  656.                 argumentType = kStandardProfileNameArg;
  657.             }
  658.         else
  659.             {
  660.             argumentType = kErrorGetting_Arg;
  661.             }
  662.         }
  663.     // No option, must be input file or profile file
  664.     else if (*argPtr)
  665.         {
  666.         argumentType = kFileName_Arg;
  667.         endPtr = argPtr;
  668.         // file name, optionally in quotes
  669.         if (*argPtr == '"')
  670.             {
  671.             ++argPtr;
  672.             ++endPtr;
  673.             while (*endPtr && *endPtr != '"')
  674.                 ++endPtr;
  675.             }
  676.         else
  677.             {
  678.             while (*endPtr && !white(*endPtr))
  679.                 ++endPtr;
  680.             }
  681.         // the special name "MFS" means all multi-file selected files
  682.         if ( endPtr == argPtr + 3
  683.           && *argPtr == 'M' && *(argPtr+1) == 'F' && *(argPtr+2) == 'S')
  684.             argumentType = kMFS_Arg;
  685.         else if (endPtr - argPtr > 4)
  686.             {
  687.             if ( *(endPtr-1) == 'o' && *(endPtr-2) == 'r'
  688.               && *(endPtr-3) == 'p' && *(endPtr-4) == '.' )
  689.                 argumentType = kProfileName_Arg;
  690.             }
  691.         }
  692.     // All done when hit a null byte
  693.     else
  694.         {
  695.         endPtr = argPtr;
  696.         }
  697.     *argPtrP = argPtr;
  698.     argLength = endPtr - argPtr;
  699.     *argLengthP = argLength;
  700.     return argumentType;
  701.     }
  702.  
  703. Boolean DoIndentDialog()
  704.     {
  705.     MenuHandle        theMenu;
  706.     DialogPtr        dPtr;
  707.     Handle            theHandle;
  708.     Rect            theBox;
  709.     Point            pt;
  710.     long            aLong;
  711.     short              theID, menuItem;
  712.     short            kind, itemHit, badChar, theType;
  713.     char            mText[64];
  714.     Boolean            checkValue;
  715.     UserItemUPP        IndentPopProcUPP;
  716.     UserItemUPP        ButtonProcUPP;
  717.     
  718.     if (!GetAndAlignDialog(IndentDlogID))
  719.         return(FALSE);
  720.     dPtr = GetNewDialog(IndentDlogID, NULL, (WindowPtr)-1L);
  721.     
  722.     CreateIndentProgramResourcePopups();
  723.     
  724.     /* attach procs for popups */
  725.     IndentPopProcUPP = NewUserItemProc(IndentPopProc);
  726.     
  727.     GetDItem(dPtr, ProfilePopup, &kind, &theHandle, &theBox);
  728.     SetDItem(dPtr, ProfilePopup, kind, (Handle)IndentPopProcUPP, &theBox);
  729.     
  730.     GetDItem(dPtr, OutputPopup, &kind, &theHandle, &theBox);
  731.     SetDItem(dPtr, OutputPopup, kind, (Handle)IndentPopProcUPP, &theBox);
  732.     
  733.     GetDItem(dPtr, InputPopup, &kind, &theHandle, &theBox);
  734.     SetDItem(dPtr, InputPopup, kind, (Handle)IndentPopProcUPP, &theBox);
  735.  
  736.     /*...and buttons */
  737.     ButtonProcUPP = NewUserItemProc(ButtonProc);
  738.     GetDItem(dPtr, RunUserItem, &kind, &theHandle, &theBox);
  739.     SetDItem(dPtr,RunUserItem, kind, (Handle)ButtonProcUPP, &theBox);
  740.  
  741.     /* init IndentSetup */
  742.     gIndentSetup.profileName = gIndentSetup.inputName = NULL;
  743.     gIndentSetup.outputName = NULL;
  744.     ResetIndentSetup(dPtr); /* clears popup contents too */
  745.     
  746.     SetPopupMark(MainProfileID, gIndentSetup.profileMenuNum);
  747.     SetPopupMark(InputID, gIndentSetup.inputType);
  748.     SetPopupMark(OutputID, gIndentSetup.outputType);
  749.     
  750.     ShowWindow(dPtr);
  751.     SetPort(dPtr);
  752.     
  753.     
  754.     InitCursor();
  755.     itemHit = 99;
  756.     while (itemHit > 2) /* ie not Run/Cancel */
  757.         {
  758.         ModalDialog(NULL, &itemHit);
  759.         switch (itemHit)
  760.             {
  761.         case ProfilePopup:
  762.             /* Treat any pick from this menu as request
  763.             to change main profile */
  764.             GetDItem(dPtr, ProgramStat, &kind, &theHandle, &theBox);
  765.             InvertRect(&theBox);
  766.             pt.v = theBox.top;
  767.             pt.h = theBox.right;
  768.             LocalToGlobal(&pt);
  769.             theMenu = GetMHandle(MainProfileID);
  770.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, 1);
  771.             theID = HiWord(aLong);
  772.             menuItem = LoWord(aLong);
  773.             InvertRect(&theBox);
  774.             if (menuItem > 0) /* get profile, if not canned set it up */
  775.                 {
  776.                 GetIndentProfileName(dPtr, menuItem);
  777.                 RedrawItem(dPtr, itemHit);
  778.                 }
  779.         break;
  780.         case InputPopup:
  781.             GetDItem(dPtr, InputStat, &kind, &theHandle, &theBox);
  782.             InvertRect(&theBox);
  783.             pt.v = theBox.top;
  784.             pt.h = theBox.right;
  785.             LocalToGlobal(&pt);
  786.             theMenu = GetMHandle(InputID);
  787.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, gIndentSetup.inputType);
  788.             theID = HiWord(aLong);
  789.             menuItem = LoWord(aLong);
  790.             InvertRect(&theBox);
  791.             if (menuItem > 0)
  792.                 gIndentSetup.inputType = menuItem;
  793.             if (menuItem == inPop.frontSelected)
  794.                 {
  795.                 ;
  796.                 }
  797.             else if (menuItem == inPop.frontAll)
  798.                 {
  799.                 ;
  800.                 }
  801.             else if (menuItem == inPop.multiSelected)
  802.                 {
  803.                 ;
  804.                 }
  805.             else if (menuItem == inPop.specificFile)
  806.                 {
  807.                 GetInputFileName();
  808.                 }
  809.             if (menuItem > 0 && menuItem != inPop.specificFile)
  810.                 {
  811.                 if (gIndentSetup.inputName)
  812.                     {
  813.                     DisposPtr(gIndentSetup.inputName);
  814.                     gIndentSetup.inputName = NULL;
  815.                     SetItem(theMenu, inPop.specificFile, (StringPtr)"\pSelect input file...");
  816.                     }
  817.                 }
  818.             if (menuItem > 0)
  819.                 {
  820.                 SetPopupMark(InputID, gIndentSetup.inputType);
  821.                 RedrawItem(dPtr, itemHit);
  822.                 MaintainOutputPopup();
  823.                 RedrawItem(dPtr, OutputPopup);
  824.                 }
  825.         break;
  826.         case OutputPopup:
  827.             GetDItem(dPtr, OutputStat, &kind, &theHandle, &theBox);
  828.             InvertRect(&theBox);
  829.             pt.v = theBox.top;
  830.             pt.h = theBox.right;
  831.             LocalToGlobal(&pt);
  832.             theMenu = GetMHandle(OutputID);
  833.             aLong = PopUpMenuSelect(theMenu, pt.v, pt.h, 1);
  834.             theID = HiWord(aLong);
  835.             menuItem = LoWord(aLong);
  836.             InvertRect(&theBox);
  837.             if (menuItem > 0)
  838.                 {
  839.                 gIndentSetup.outputType = menuItem;
  840.                 SetPopupMark(OutputID, gIndentSetup.outputType);
  841.                 RedrawItem(dPtr, itemHit);
  842.                 }
  843.         break;
  844.         case AboutIndent:
  845.             OKStopAlert("Copyright © 1991, Free Software Foundation.\r\
  846. Indent comes with ABSOLUTELY NO WARRANTY.  This is free software, and \
  847. you are welcome to distribute it under the terms of the GNU General \
  848. Public License, which covers both the warranty information and the \
  849. terms for redistribution.\r\
  850. You should have received a copy of the GNU General Public License along \
  851. with this program (see COPYING Indent); if not, write to the Free Software Foundation, Inc., \
  852. 675 Mass Ave, Cambridge, MA 02139, USA.");
  853.         break;
  854.             }
  855.         }
  856.     
  857.     // TEST ONLY DELETE
  858.     // DisposeRoutineDescriptor(IndentPopProcUPP);
  859.     // DisposeRoutineDescriptor(ButtonProcUPP);
  860.  
  861.     /* cancelled? */
  862.     if (itemHit == 2) /* cancel */
  863.         {
  864.         if (gIndentSetup.profileName)
  865.             DisposPtr(gIndentSetup.profileName);
  866.         if (gIndentSetup.inputName)
  867.             DisposPtr(gIndentSetup.inputName);
  868.         if (gIndentSetup.outputName)
  869.             DisposPtr(gIndentSetup.outputName);
  870.         DisposDialog(dPtr);
  871.         DestroyIndentPopups();
  872.         return(FALSE);
  873.         }
  874.     /* translate to "commmand" line */
  875.     if(!GetCommandLineFromDlogResult())
  876.         {
  877.         DisposDialog(dPtr);
  878.         DestroyIndentPopups();
  879.         return(FALSE);
  880.         }
  881.     
  882.     //GetCheck (dPtr, ShowOut, &checkValue);
  883.     //gIndentSetup.showOut = checkValue;
  884.     DisposDialog(dPtr);
  885.     DestroyIndentPopups();
  886.     return(TRUE);
  887.     }
  888.  
  889. /* Called for each run.
  890. The input selection popup depends on what extensions have
  891. been passed in for this run. A largely pointless exercise in
  892. dynamically maintaining a menu, yet Apple disapproves of
  893. disabling items in a popup menu, so this approach has the
  894. virtue of being not-officially-frowned-upon. */
  895. void CreateIndentProgramResourcePopups()
  896.     {
  897.     MenuHandle         theMenu;
  898.     
  899.     CreateProfilePopup();
  900.     
  901.     theMenu = NewMenu(InputID, (StringPtr)"\pInput");
  902.     if (HasGetFrontText())
  903.         {
  904.         inPop.frontSelected = 1;
  905.         inPop.frontAll = 2;
  906.         AppendMenu(theMenu, (StringPtr)"\pFront text selection");
  907.         AppendMenu(theMenu, (StringPtr)"\pAll of front text");
  908.         }
  909.     else
  910.         {
  911.         inPop.frontSelected = inPop.frontAll = 0;
  912.         }
  913.     if (HasGetNextMultiFile())
  914.         {
  915.         if (inPop.frontSelected)
  916.             inPop.multiSelected = 3;
  917.         else
  918.             inPop.multiSelected = 1;
  919.         AppendMenu(theMenu, (StringPtr)"\pMFS selected files");
  920.         }
  921.     else
  922.         inPop.multiSelected = 0;
  923.     if (inPop.frontSelected || inPop.multiSelected)
  924.         {
  925.         if (inPop.multiSelected == 3) /* all present */
  926.             inPop.specificFile = 5;
  927.         else if (inPop.multiSelected == 1) /* front options missing */
  928.             inPop.specificFile = 3;
  929.         else /* multi missing, therefore hasgetfront */
  930.             inPop.specificFile = 4;
  931.         AppendMenu(theMenu, (StringPtr)"\p-");
  932.         }
  933.     else
  934.         {
  935.         inPop.specificFile = 1;
  936.         }
  937.     /* This option is always available */
  938.     AppendMenu(theMenu, (StringPtr)"\pSelect input file...");
  939.     InsertMenu(theMenu, -1);
  940.     
  941.     // Output popup is dynamically created according to the current
  942.     // input option.
  943.     MaintainOutputPopup();    //creates it if necessary
  944.     }
  945.  
  946. /* The possibilities are:
  947. "\pBack up and overwrite": if MFS or one specific file
  948. "\pRename with number"     : one specific file only
  949. "\pTo $tempStdOut"         : if one specific file or stdin
  950. */
  951. void MaintainOutputPopup()
  952.     {
  953.     MenuHandle             theMenu;
  954.     short                n;
  955.     short                i;
  956.     OutputPopupItems    outPopOld = outPop; // sa
  957.     Boolean                resetType = false;
  958.     
  959.     theMenu = GetMHandle(OutputID);
  960.     if (theMenu == NULL)
  961.         {
  962.         theMenu = NewMenu(OutputID, (StringPtr)"\pOutput");
  963.         InsertMenu(theMenu, -1);
  964.         resetType = true;
  965.         }
  966.     
  967.     // Clean out the menu, we will rebuild it here
  968.     n = CountMItems(theMenu);
  969.     for (i = n; i >= 1; --i)
  970.         {
  971.         DeleteMenuItem(theMenu, i);
  972.         }
  973.     // Which input item is selected?
  974.     // stdin
  975.     if ( inPop.frontSelected == gIndentSetup.inputType
  976.       || inPop.frontAll == gIndentSetup.inputType )
  977.         {
  978.         outPop.replaceWithBackup = outPop.renameWithNumber = 0;
  979.         outPop.toStandardOut = 1;
  980.         AppendMenu(theMenu, (StringPtr)"\pTo $tempStdOut");
  981.         }
  982.     // MFS
  983.     else if (inPop.multiSelected == gIndentSetup.inputType)
  984.         {
  985.         outPop.toStandardOut = outPop.renameWithNumber = 0;
  986.         outPop.replaceWithBackup = 1;
  987.         AppendMenu(theMenu, (StringPtr)"\pBack up and overwrite");
  988.         }
  989.     else if (inPop.specificFile == gIndentSetup.inputType)
  990.         {
  991.         outPop.replaceWithBackup = 1;
  992.         outPop.renameWithNumber = 2;
  993.         outPop.toStandardOut = 3;
  994.         AppendMenu(theMenu, (StringPtr)"\pBack up and overwrite");
  995.         AppendMenu(theMenu, (StringPtr)"\pRename with number");
  996.         AppendMenu(theMenu, (StringPtr)"\pTo $tempStdOut");
  997.         }
  998.     else
  999.         {
  1000.         ;// error
  1001.         }
  1002.     
  1003.     // Should we reset type?
  1004.     if ( outPop.replaceWithBackup != outPopOld.replaceWithBackup
  1005.       || outPop.renameWithNumber != outPopOld.renameWithNumber
  1006.       || outPop.toStandardOut != outPopOld.toStandardOut )
  1007.         gIndentSetup.outputType = 1;
  1008.     
  1009.     // Restore item mark.
  1010.     SetPopupMark(OutputID, gIndentSetup.outputType);
  1011.     }
  1012.  
  1013. /* When Indent is called, the current working folder is the one
  1014. containing Indent - search it for the folder "Indent profiles".
  1015. If found, add all TEXT files whose names end with ".pro" to the
  1016. program popup, in alpha order. */
  1017. void CreateProfilePopup()
  1018.     {
  1019.     MenuHandle         theMenu;
  1020.     char            curvolName[32];
  1021.     long            theDirID;
  1022.     
  1023.     theMenu = NewMenu(MainProfileID, (StringPtr)"\pProfiles");
  1024.     AppendMenu(theMenu, (StringPtr)"\pSelect unlisted profile...");
  1025.     AppendMenu(theMenu, (StringPtr)"\p-");
  1026.     AppendMenu(theMenu, (StringPtr)"\p-");
  1027.     AppendMenu(theMenu, (StringPtr)"\pGNU, the default");
  1028.     AppendMenu(theMenu, (StringPtr)"\pK & R");
  1029.     AppendMenu(theMenu, (StringPtr)"\pBerkeley");
  1030.     
  1031.     
  1032.     if (theDirID = FindIndentProfileFolder(curvolName, (char *)"\pIndent profiles"))
  1033.         AddProfilesToMenu(curvolName, theDirID, theMenu);
  1034.     InsertMenu(theMenu, -1);
  1035.     }
  1036.  
  1037. long FindIndentProfileFolder(char *curvolName, char *folderName)
  1038.     {
  1039.     HFileInfo    myCPB;
  1040.     WDPBRec        theParms;
  1041.     char        fName[32];
  1042.     long        theDirID;
  1043.     short            codeVRefNum, index = 1, len;
  1044.     OSErr        err;
  1045.     
  1046.     
  1047.     GetVol(NULL, &codeVRefNum);
  1048.     /* Extract "\pVolName:" and dirID for code resource folder */
  1049.     theParms.ioNamePtr = (StringPtr)(curvolName);
  1050.     theParms.ioVRefNum = codeVRefNum;
  1051.     theParms.ioWDIndex = 0;
  1052.     theParms.ioWDProcID = 0;
  1053.     if (PBGetWDInfo(&theParms,false))
  1054.         {
  1055.         OKStopAlert("Bad working directory");
  1056.         return(0L);
  1057.         }
  1058.     len = curvolName[0];
  1059.     curvolName[len + 1] = ':';
  1060.     curvolName[0] = len + 1;
  1061.     
  1062.     theDirID = theParms.ioWDDirID;
  1063.     
  1064.     myCPB.ioNamePtr = (StringPtr)fName;
  1065.     myCPB.ioVRefNum = theParms.ioWDVRefNum;
  1066.     do
  1067.         {
  1068.         myCPB.ioFDirIndex = index;
  1069.         myCPB.ioDirID = theDirID;
  1070.         if ((err = PBGetCatInfo((CInfoPBPtr)&myCPB, FALSE)) == noErr)
  1071.             {
  1072.             if (((myCPB.ioFlAttrib>>4) & 0x01) == 1) /* a folder */
  1073.                 {
  1074.                 if (PEqualStrs((Byte *)fName, (Byte *)folderName))
  1075.                     return(myCPB.ioDirID);
  1076.                 }
  1077.             }
  1078.         ++index;
  1079.         } while (err == noErr);
  1080.     /* OKStopAlert("hawk program folder not found"); if you're testing */
  1081.     return(0L);
  1082.     }
  1083.  
  1084. void AddProfilesToMenu(char *curvolName, long theDirID, MenuHandle theMenu)
  1085.     {
  1086.     HFileInfo    myCPB;
  1087.     WDPBRec        theParms;
  1088.     HVolumeParam    vParms;
  1089.     char        fName[32], volName[32];
  1090.     short            index = 1, theVolRef, vRefNum;
  1091.     OSErr        err;
  1092.     Boolean        firstAdd = TRUE;
  1093.     
  1094.     /* Some shenanigans to open working directory for code resources */
  1095.     BlockMove(curvolName, volName, 32);
  1096.     vParms.ioCompletion = NULL;
  1097.     vParms.ioNamePtr = (StringPtr)(volName);
  1098.     vParms.ioVRefNum = -32768;
  1099.     vParms.ioVolIndex = -1;
  1100.     if (PBHGetVInfo((HParmBlkPtr)&vParms, FALSE))
  1101.         theVolRef = 0;
  1102.     else
  1103.         theVolRef = vParms.ioVRefNum;
  1104.     theParms.ioCompletion = NULL;
  1105.     theParms.ioVRefNum = theVolRef;
  1106.     theParms.ioNamePtr = NULL;
  1107.     theParms.ioWDDirID = theDirID;
  1108.     theParms.ioWDProcID = 'ERIK';
  1109.     if (PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  1110.         vRefNum = 0;
  1111.     else
  1112.         vRefNum = theParms.ioVRefNum;
  1113.     
  1114.     theParms.ioNamePtr = NULL;
  1115.     theParms.ioVRefNum = vRefNum;
  1116.     theParms.ioWDIndex = 0;
  1117.     theParms.ioWDProcID = 0;
  1118.     if (PBGetWDInfo(&theParms,false))
  1119.         return;
  1120.     gIndentSetup.defaultVRefNum = vRefNum; /* saved away, folder is left open */
  1121.     
  1122.     myCPB.ioNamePtr = (StringPtr)fName;
  1123.     myCPB.ioVRefNum = theParms.ioWDVRefNum;
  1124.     do
  1125.         {
  1126.         myCPB.ioFDirIndex = index;
  1127.         myCPB.ioDirID = theDirID;
  1128.         if ((err = PBGetCatInfo((CInfoPBPtr)&myCPB, FALSE)) == noErr)
  1129.             {
  1130.             if (((myCPB.ioFlAttrib>>4) & 0x01) != 1) /* a file */
  1131.                 {
  1132.                 /* fName holds name of file */
  1133.                 /* Is it the right kind of file? */
  1134.                 if (myCPB.ioFlFndrInfo.fdType == 'TEXT'
  1135.                     && fName[0] >= 5
  1136.                     && fName[fName[0]] == 'o'
  1137.                     && fName[fName[0]-1] == 'r'
  1138.                     && fName[fName[0]-2] == 'p'
  1139.                     && fName[fName[0]-3] == '.' )
  1140.                     {
  1141.                     if (firstAdd)
  1142.                         {
  1143.                         AppendMenu(theMenu, (StringPtr)"\p-");
  1144.                         firstAdd = FALSE;
  1145.                         }
  1146.                     AlphaAppendMenu(theMenu, 8, fName);
  1147.                     }
  1148.                 }
  1149.             }
  1150.         ++index;
  1151.         } while (err == noErr);
  1152.     if (firstAdd) /* none added */
  1153.         {
  1154.         theParms.ioVRefNum = vRefNum;
  1155.         PBCloseWD(&theParms, FALSE);
  1156.         }
  1157.     }
  1158.  
  1159. void AlphaAppendMenu(MenuHandle theMenu, short lowPoint, char *name)
  1160.     {
  1161.     short        newItemNum,
  1162.             highPoint = CountMItems(theMenu);
  1163.     
  1164.     
  1165.     newItemNum = AlphaMenuPos(name, theMenu, highPoint, lowPoint);
  1166.     if (newItemNum > 0)
  1167.         {
  1168.         /*error duplicate - unlikely for file list. */
  1169.         return;
  1170.         }
  1171.     else
  1172.         newItemNum = -newItemNum;
  1173.     InsMenuItem(theMenu, (StringPtr)"\pa", newItemNum - 1);
  1174.     SetItem(theMenu, newItemNum, (StringPtr)name);
  1175.     }
  1176.  
  1177. /* Binary search existing menu for match against nameptr; if
  1178. match return lowPoint:highPoint. If no match let n = where name would
  1179. be inserted, range lowPoint:highPoint+1, return -n. For insertion, do
  1180. InsMenuItem(theMenu, (StringPtr)"\pa", n - 1); -see just above.
  1181. */
  1182. short AlphaMenuPos(char *name, MenuHandle theMenu, short highPoint, short lowPoint)
  1183.     {
  1184.     short        index;
  1185.     
  1186.     if (highPoint < lowPoint)
  1187.         return(-lowPoint);
  1188.     
  1189.     do
  1190.         {
  1191.         index = (lowPoint + highPoint)/2;
  1192.         if (MenuCompare(name, theMenu, index) < 0)
  1193.             highPoint = index - 1;
  1194.         else
  1195.             lowPoint = index + 1;
  1196.         } while (MenuCompare(name, theMenu, index) && lowPoint <= highPoint);
  1197.     if (!MenuCompare(name, theMenu, index)) /* a hit */
  1198.         return(index);
  1199.     /* lowPoint went "one too far", ie it is number that name will be after insertion */
  1200.     return(-lowPoint);
  1201.     }
  1202.  
  1203. short MenuCompare(char *name, MenuHandle theMenu, short index)
  1204.     {
  1205.     char            itemStr[64];
  1206.     
  1207.     GetItem(theMenu, index, (StringPtr)itemStr);
  1208.     /* Fudge, both mark and item strs are pascal, but warp to ptr/len vs pascal.
  1209.     Sorry folks, doing it this way because I had the tested code already. */
  1210.     return(PtrLenPascalCompare(name + 1L, name[0], itemStr));
  1211.     }
  1212.  
  1213. /* Compare, for ptr, len vs pascal strings.
  1214. Compare pattern with target, returning number
  1215. reflecting alphabetical rather than ascii order.
  1216. */
  1217. typedef Byte *BPtr;
  1218. short PtrLenPascalCompare(Ptr spatPtr, short patLen, Ptr stargetPtr)
  1219.     {
  1220.     BPtr    patPtr = (BPtr)spatPtr,
  1221.             patEndPtr = patPtr + patLen,
  1222.             curPtr = (BPtr)stargetPtr + 1,
  1223.             curEndPtr = curPtr + (unsigned short)(stargetPtr[0]);
  1224.     short        i, j;
  1225.     
  1226.     while (patPtr < patEndPtr && curPtr < curEndPtr && *patPtr == *curPtr)
  1227.         {
  1228.         ++patPtr;
  1229.         ++curPtr;
  1230.         }
  1231.     
  1232.     if (patPtr == patEndPtr && curPtr == curEndPtr) /* exact match */
  1233.         return(0);
  1234.     if (patPtr == patEndPtr && curPtr != curEndPtr) /* pattern too short */
  1235.         return(-1);
  1236.     if (patPtr != patEndPtr && curPtr == curEndPtr) /* starget too short */
  1237.         return(1);
  1238.     
  1239.     /* true miscompare within string */
  1240.     i = (short)*patPtr;
  1241.     j = (short)*curPtr;
  1242.     /* sequence: nonalpha, AaBbCc...Zz */
  1243.     /* 'A' = 65, 'a' = 97; move 'U' to 'U'*2 + 256, 'u' to 'u'*2 + 193 */
  1244.     /* 'A' -> 386, 'B' -> 388, 'a' -> 387, 'b' -> 389 etc */
  1245.     if ('A' <= i && i <= 'Z')
  1246.         i = i*2 + 256;
  1247.     else if ('a' <= i && i <= 'z')
  1248.         i = i*2 + 193;
  1249.     if ('A' <= j && j <= 'Z')
  1250.         j = j*2 + 256;
  1251.     else if ('a' <= j && j <= 'z')
  1252.         j = j*2 + 193;
  1253.     return(i - j);
  1254.     }
  1255.  
  1256. /* Somebody's watching, so draw in the popup menus. */
  1257. pascal void IndentPopProc(WindowPtr wdPtr, short item)
  1258.     {
  1259.     GrafPtr        savePort;
  1260.     short        kind, menuNum, i, n, markChar;
  1261.     Handle        theHandle;
  1262.     MenuHandle    theMenu;
  1263.     Rect        box;
  1264.     Byte        mText[64];
  1265.     
  1266.     GetPort(&savePort);
  1267.     SetPort (wdPtr);
  1268.     
  1269.     if (item == ProfilePopup)
  1270.         theMenu = GetMHandle(MainProfileID);
  1271.     else if (item == InputPopup)
  1272.         theMenu = GetMHandle(InputID);
  1273.     else if (item == OutputPopup)
  1274.         theMenu = GetMHandle(OutputID);
  1275.     else
  1276.         return;
  1277.     n = CountMItems(theMenu);
  1278.     for (i = 1; i <= n; ++i)
  1279.         {
  1280.         GetItemMark(theMenu, i, &markChar);
  1281.         if (markChar == ' ')
  1282.             break;
  1283.         }
  1284.     if (i <= n)
  1285.         menuNum = i;
  1286.     else
  1287.         menuNum = 1;
  1288.     
  1289.     GetDItem(wdPtr, item, &kind, &theHandle, &box);
  1290.     GetItem(theMenu, menuNum, mText);
  1291.     EraseRect(&box);
  1292.     TextBox(&(mText[1]),(unsigned char)(mText[0]),&box,teJustLeft);
  1293.     box.left -= 1;
  1294.     box.top -= 1;
  1295.     box.right += 1;
  1296.     box.bottom += 1;
  1297.     FrameRect(&box);
  1298.     MoveTo(box.left + 1, box.bottom);
  1299.     LineTo(box.right, box.bottom);
  1300.     MoveTo(box.right, box.top + 1);
  1301.     LineTo(box.right, box.bottom);
  1302.     SetPort(savePort);
  1303.     }
  1304.  
  1305. pascal void ButtonProc(WindowPtr wdPtr, short item)
  1306.     {
  1307.     GrafPtr            savePort;
  1308.     PenState        savePen;
  1309.     Handle           h;
  1310.     Rect            theBox;
  1311.     short            theType, ovalSize, i;
  1312.     
  1313.     GetDItem(wdPtr,item,&theType,&h,&theBox);
  1314.     GetPort(&savePort);
  1315.     SetPort(wdPtr);
  1316.     GetPenState(&savePen);
  1317.     PenNormal();
  1318.     PenSize(2,2);
  1319.     
  1320.     InsetRect(&theBox,-3,-3);
  1321.     ovalSize = (theBox.bottom + 8 - theBox.top) / 2;    
  1322.     FrameRoundRect(&theBox,ovalSize,ovalSize);
  1323.     
  1324.     SetPenState(&savePen);
  1325.     SetPort(savePort);
  1326.     }
  1327.  
  1328. void ResetIndentSetup(DialogPtr dPtr)
  1329.     {
  1330.     MenuHandle    theMenu;
  1331.     short        itemHit, numItems;
  1332.     
  1333.     gIndentSetup.profileMenuNum = gIndentSetup.outputType = gIndentSetup.inputType = 1;
  1334.     gIndentSetup.showOut = false;
  1335.     if (gIndentSetup.profileName)
  1336.         {
  1337.         DisposPtr(gIndentSetup.profileName);
  1338.         gIndentSetup.profileName = NULL;
  1339.         }
  1340.     if (gIndentSetup.inputName)
  1341.         {
  1342.         DisposPtr(gIndentSetup.inputName);
  1343.         gIndentSetup.inputName = NULL;
  1344.         }
  1345.     if (gIndentSetup.outputName)
  1346.         {
  1347.         DisposPtr(gIndentSetup.outputName);
  1348.         gIndentSetup.outputName = NULL;
  1349.         }
  1350.     theMenu = GetMHandle(MainProfileID);
  1351.     SetItem(theMenu, 1, (StringPtr)"\pSelect unlisted profile...");
  1352.     theMenu = GetMHandle(InputID);
  1353.     SetItem(theMenu, inPop.specificFile, (StringPtr)"\pSelect input file...");
  1354.     
  1355.     MaintainOutputPopup();
  1356.     }
  1357.  
  1358. /* A space character is used to mark the currently-selected item,
  1359. avoiding the horror of attempting to access global variables
  1360. within the pascal callback above, within a CODE resource. */
  1361. void SetPopupMark(short theMenuID, short newItem)
  1362.     {
  1363.     short        i, n, markChar;
  1364.     MenuHandle    theMenu;
  1365.     
  1366.     theMenu = GetMHandle(theMenuID);
  1367.     n = CountMItems(theMenu);
  1368.     for (i = 1; i <= n; ++i)
  1369.         {
  1370.         GetItemMark(theMenu, i, &markChar);
  1371.         if (markChar == ' ')
  1372.             {
  1373.             if (i == newItem)
  1374.                 return;
  1375.             else
  1376.                 SetItemMark(theMenu, i, 0);
  1377.             }
  1378.         else if (i == newItem)
  1379.             {
  1380.             markChar = ' ';
  1381.             SetItemMark(theMenu, i, markChar);
  1382.             }
  1383.         }
  1384.     }
  1385.  
  1386. void GetIndentProfileName(DialogPtr dPtr, short item)
  1387.     {
  1388.     MenuHandle    theMenu;
  1389.     Point         where;
  1390.     SFReply     reply;
  1391.     SFTypeList     types;
  1392.     long        len;
  1393.     short            numTypes;
  1394.     Boolean        userLocated;
  1395.     
  1396.     if (item == 1)
  1397.         {
  1398.         /* display dialog, get program name and input file name */
  1399.         types[0] = 'TEXT';
  1400.         types[1] = 'RRRS';
  1401.         numTypes = 2;
  1402.         GetDlogOrigin (getDlgID, &where);
  1403.         SFGetFile (where, (StringPtr)"\p", NULL, numTypes, types, NULL, &reply);
  1404.         if (!reply.good)
  1405.             return;
  1406.         userLocated = TRUE;
  1407.         }
  1408.     else /* either listed or unlisted program - the unlisted one is number 3 */
  1409.         {
  1410.         if (item == gIndentSetup.profileMenuNum) /* nothing new */
  1411.             return;
  1412.         theMenu = GetMHandle(MainProfileID);
  1413.         GetItem(theMenu, item, (StringPtr)(reply.fName));
  1414.         userLocated = FALSE;
  1415.         }
  1416.     /* reset gIndentSetup, partial */
  1417.     if (gIndentSetup.profileName)
  1418.         {
  1419.         DisposPtr(gIndentSetup.profileName);
  1420.         gIndentSetup.profileName = NULL;
  1421.         }
  1422.     
  1423.     gIndentSetup.profileName = NewPtr(256);
  1424.     if (MemError() != noErr)
  1425.         {
  1426.         gIndentSetup.profileVRefNum = 0;
  1427.         MemoryAlert();
  1428.         HiliteDlgControl(dPtr, 1, 255);
  1429.         return;
  1430.         }
  1431.     if (userLocated)
  1432.         gIndentSetup.profileVRefNum = reply.vRefNum;
  1433.     else if (item == 3)
  1434.         gIndentSetup.profileVRefNum = gIndentSetup.otherVRefNum;
  1435.     else
  1436.         gIndentSetup.profileVRefNum = gIndentSetup.defaultVRefNum;
  1437.     if (userLocated)
  1438.         gIndentSetup.profileMenuNum = 3;
  1439.     else
  1440.         gIndentSetup.profileMenuNum = item;
  1441.     AppendPStr((Byte *)(FullPathNameFromVRefNum(gIndentSetup.profileVRefNum,(Byte *)(gIndentSetup.profileName))),
  1442.         (Byte *)(reply.fName));
  1443.     SetPtrSize(gIndentSetup.profileName, gIndentSetup.profileName[0]+1);
  1444.     PtoCstr((StringPtr)gIndentSetup.profileName); /* also done by LoadIndentDlogFromHS */
  1445.     /* Restore saved invocation */
  1446.     if (userLocated || item > 6)
  1447.         InitIndentFromProfile(gIndentSetup.profileName);
  1448.     theMenu = GetMHandle(MainProfileID);
  1449.     if (userLocated)
  1450.         SetItem(theMenu, 3, reply.fName);
  1451.     /* Enable Run and SaveSettings buttons */
  1452.     HiliteDlgControl(dPtr, 1, 0);
  1453.     if (item == 1)
  1454.         item = 3;
  1455.     SetPopupMark(MainProfileID, item);
  1456.  
  1457.     /* Redraw done by caller */
  1458.     }
  1459.  
  1460. void GetInputFileName()
  1461.     {
  1462.     MenuHandle    theMenu;
  1463.     Point         where;
  1464.     SFReply     reply;
  1465.     SFTypeList     types;
  1466.     long        len;
  1467.     short            numTypes;
  1468.     
  1469.     /* display dialog, get program name and input file name */
  1470.     types[0] = 'TEXT';
  1471.     types[1] = 'RRRS';
  1472.     numTypes = 2;
  1473.     GetDlogOrigin (getDlgID, &where);
  1474.     SFGetFile (where, (StringPtr)"\p", NULL, numTypes, types, NULL, &reply);
  1475.     if (!reply.good)
  1476.         return;
  1477.     
  1478.     if (gIndentSetup.inputName)
  1479.         {
  1480.         DisposPtr(gIndentSetup.inputName);
  1481.         gIndentSetup.inputName = NULL;
  1482.         }
  1483.     gIndentSetup.inputName = NewPtr(256);
  1484.     if (MemError() != noErr)
  1485.         {
  1486.         MemoryAlert();
  1487.         return;
  1488.         }
  1489.     AppendPStr((Byte *)(FullPathNameFromVRefNum(reply.vRefNum,(Byte *)(gIndentSetup.inputName))),
  1490.         (Byte *)(reply.fName));
  1491.     PtoCstr((StringPtr)gIndentSetup.inputName);
  1492.     /* Set menu */
  1493.     theMenu = GetMHandle(InputID);
  1494.     SetItem(theMenu, inPop.specificFile, reply.fName);
  1495.     }
  1496.  
  1497. void DestroyIndentPopups()
  1498.     {
  1499.     MenuHandle    theMenu;
  1500.     
  1501.     theMenu = GetMHandle(MainProfileID);
  1502.     if (!theMenu)
  1503.         return;
  1504.     DeleteMenu(MainProfileID);
  1505.     DisposeMenu(theMenu);
  1506.     
  1507.     theMenu = GetMHandle(OutputID);
  1508.     if (!theMenu)
  1509.         return;
  1510.     DeleteMenu(OutputID);
  1511.     DisposeMenu(theMenu);
  1512.     
  1513.     theMenu = GetMHandle(InputID);
  1514.     if (!theMenu)
  1515.         return;
  1516.     DeleteMenu(InputID);
  1517.     DisposeMenu(theMenu);
  1518.     }
  1519.  
  1520. /* Command line for awk proper, generated from user
  1521. dialog choices and variable entries.
  1522. Indent -fProgname -fLibraries -vVariables -- inputfiles
  1523. */
  1524. Boolean GetCommandLineFromDlogResult()
  1525.     {
  1526.     long    len;
  1527.     short    i;
  1528.     Boolean    passCannedProfile = false;
  1529.     
  1530.     if (gIndentSetup.inputType == inPop.specificFile && !(gIndentSetup.inputName))
  1531.         {
  1532.         /* A suspicious case, arrived at thru:
  1533.         - pick "Specific file..." option for input, and then cancel
  1534.             to, in effect, select the empty file.
  1535.         So return false */
  1536.         return false;
  1537.         }
  1538.     argc = 0;
  1539.     argv = (char **)malloc( sizeof(char *) * NUMARGVS );
  1540.     if (argv == NULL)
  1541.         {
  1542.         CleanUpAfterIndent();
  1543.         return(FALSE);
  1544.         }
  1545.     // Indent name always as first arg.
  1546.     len = strlen(gacc.thisCodeName);
  1547.     argv[argc] = NewPtr(len+1);
  1548.     if (!argv[argc])
  1549.         return(FALSE);
  1550.     BlockMove(gacc.thisCodeName, argv[argc], len+1);
  1551.     ++argc;
  1552.     
  1553.     // Do we need to pass a canned profile?
  1554.     if ( gIndentSetup.profileMenuNum == 1
  1555.       || (4 <= gIndentSetup.profileMenuNum && gIndentSetup.profileMenuNum <= 6) )
  1556.         {
  1557.         passCannedProfile = true;
  1558.         if ( gIndentSetup.profileMenuNum == 1
  1559.           || gIndentSetup.profileMenuNum == 4 )
  1560.             {
  1561.             argv[argc] = NewPtr(5);
  1562.             if (MemError() != noErr)
  1563.                 {
  1564.                 CleanUpAfterIndent();
  1565.                 return(FALSE);
  1566.                 }
  1567.             BlockMove("-gnu", argv[argc], 5);
  1568.             ++argc;
  1569.             }
  1570.         else if (gIndentSetup.profileMenuNum == 5)
  1571.             {
  1572.             argv[argc] = NewPtr(4);
  1573.             if (MemError() != noErr)
  1574.                 {
  1575.                 CleanUpAfterIndent();
  1576.                 return(FALSE);
  1577.                 }
  1578.             BlockMove("-kr", argv[argc], 4);
  1579.             ++argc;
  1580.             }
  1581.         else if (gIndentSetup.profileMenuNum == 6)
  1582.             {
  1583.             argv[argc] = NewPtr(6);
  1584.             if (MemError() != noErr)
  1585.                 {
  1586.                 CleanUpAfterIndent();
  1587.                 return(FALSE);
  1588.                 }
  1589.             BlockMove("-orig", argv[argc], 6);
  1590.             ++argc;
  1591.             }
  1592.         // else you added one and didn't tell me!
  1593.         }
  1594.     
  1595.     // The output options.
  1596.     if (gIndentSetup.outputType == outPop.toStandardOut)
  1597.         {
  1598.         argv[argc] = NewPtr(4);
  1599.         if (MemError() != noErr)
  1600.             {
  1601.             CleanUpAfterIndent();
  1602.             return(FALSE);
  1603.             }
  1604.         BlockMove("-st", argv[argc], 4);
  1605.         ++argc;
  1606.         
  1607.         gIndentSetup.showOut = true;
  1608.         }
  1609.     else if (gIndentSetup.outputType == outPop.renameWithNumber)
  1610.         {
  1611.         // Put "-o" followed by new file name
  1612.         argv[argc] = NewPtr(3);
  1613.         if (MemError() != noErr)
  1614.             {
  1615.             CleanUpAfterIndent();
  1616.             return(FALSE);
  1617.             }
  1618.         BlockMove("-o", argv[argc], 3);
  1619.         ++argc;
  1620.         
  1621.         // This option applies only to one specific file
  1622.         argv[argc] = GetRenumberedName(gIndentSetup.inputName);
  1623.         if (!argv[argc])
  1624.             {
  1625.             CleanUpAfterIndent();
  1626.             return(FALSE);
  1627.             }
  1628.         ++argc;
  1629.         }
  1630.     // else the standard rename with backup
  1631.     
  1632.     // Get input file if any.
  1633.     if ( gIndentSetup.inputType == inPop.frontSelected
  1634.       || gIndentSetup.inputType == inPop.frontAll )
  1635.         {
  1636.         argv[argc] = CreateStdIn(gIndentSetup.inputType == inPop.frontAll);
  1637.         if (!argv[argc])
  1638.             {
  1639.             CleanUpAfterIndent();
  1640.             return(FALSE);
  1641.             }
  1642.         ++argc;
  1643.         }
  1644.     else if (gIndentSetup.inputType == inPop.multiSelected)
  1645.         {
  1646.         if (!GetInputsFromMFS())
  1647.             {
  1648.             CleanUpAfterIndent();
  1649.             return(FALSE);
  1650.             }
  1651.         }
  1652.     else if (gIndentSetup.inputType == inPop.specificFile && gIndentSetup.inputName)
  1653.         {
  1654.         argv[argc] = gIndentSetup.inputName;
  1655.         ++argc;
  1656.         }
  1657.     
  1658.     return(TRUE);
  1659.     }
  1660.  
  1661. /* If user wants the input to be whatever is in the front text file,
  1662. get a copy of the text and write it the the file used for standard input. */
  1663. char *CreateStdIn(Boolean wholeFile)
  1664.     {
  1665.     Ptr            copyOfName;
  1666.     Handle        hText;
  1667.     long        len;
  1668.     OSErr         IOResult;
  1669.     short             refNum;
  1670.     
  1671.     // anything?
  1672.     if (HasGetFrontText())
  1673.         {
  1674.         hText = GetFrontText(wholeFile);
  1675.         }
  1676.     else
  1677.         hText = NewHandle(0);
  1678.     if (!hText)
  1679.         return(NULL);
  1680.         
  1681.     // save to standard input file
  1682.     // Delete the file.  We don't care if there's an error
  1683.     FSDelete((StringPtr)gacc.stdInFileNameP, 0);
  1684.     
  1685.     // Now try to create it. '????' is the creator. Report the file error, if any
  1686.     if (IOResult = Create((StringPtr)gacc.stdInFileNameP, 0, '????', 'TEXT'))
  1687.         {
  1688.         DisposHandle(hText);
  1689.         OKStopAlert("Standard input file could not be created.");
  1690.         return(NULL);
  1691.         }
  1692.     
  1693.     if (IOResult = FSOpen ((StringPtr)gacc.stdInFileNameP, 0, &refNum))
  1694.         {
  1695.         DisposHandle(hText);
  1696.         OKStopAlert("Standard input file could not be opened.");
  1697.         return(NULL);
  1698.         }
  1699.     len = GetHandleSize(hText);
  1700.     if (IOResult = FSWrite (refNum, &len, *hText))
  1701.         {
  1702.         FSClose (refNum);
  1703.         DisposHandle(hText);
  1704.         OKStopAlert("Standard input file could not be written to.");
  1705.         return(NULL);
  1706.         }
  1707.     FSClose (refNum);
  1708.     DisposHandle(hText);
  1709.     // return ptr to copy of gacc.stdInFileName if success, or NULL
  1710.     len = strlen(gacc.stdInFileName);
  1711.     copyOfName = NewPtr(len+1);
  1712.     if (!copyOfName)
  1713.         return(NULL);
  1714.     BlockMove(gacc.stdInFileName, copyOfName, len+1);
  1715.     return(copyOfName);
  1716.     }
  1717.  
  1718. /* Build list of files from multi-file search or equivalent selection.
  1719. This version, concoct full path name for each file.
  1720. Next version, use dirID and save much space. */
  1721. Boolean GetInputsFromMFS()
  1722.     {
  1723.     char            **newArgv;
  1724.     Byte            *tempPtr, *endPtr;
  1725.     short            whichPane, index, vRefNum, lastvrefnum = 0;
  1726.     char            fileName[32];
  1727.     
  1728.     if (!HasGetNextMultiFile()) return(FALSE);
  1729.     /* determine which file to search next */
  1730.     whichPane = -1;
  1731.     GetNextMultiFile(&whichPane, &index, &vRefNum, fileName, FALSE);
  1732.     if (index < 0)
  1733.         return(FALSE);
  1734.     while (index >= 0)
  1735.         {
  1736.         tempPtr = (Byte *)malloc(256);
  1737.         if (tempPtr == NULL)
  1738.             return FALSE;
  1739.         /* This is a prime target for optimizing, since it does a lot of
  1740.         disk-pounding to retrieve the full path name. Detecting a run of
  1741.         the same vrefnum certainly helps.*/
  1742.         if (vRefNum != lastvrefnum) /* do it the hard way */
  1743.         AppendPStr((Byte *)(FullPathNameFromVRefNum(vRefNum, tempPtr)),
  1744.                 (Byte *)(fileName));
  1745.         else
  1746.             {
  1747.             BlockMove(argv[argc-1], (Ptr)tempPtr, 256);
  1748.             CtoPstr((Ptr)tempPtr);
  1749.             /* strip previous file name */
  1750.             endPtr = tempPtr + tempPtr[0];
  1751.             while (*endPtr != ':')
  1752.                 --endPtr;
  1753.             tempPtr[0] = (unsigned char)(endPtr - tempPtr);
  1754.             /* append new file name */
  1755.             AppendPStr(tempPtr, (Byte *)(fileName));
  1756.             }
  1757.         PtoCstr((StringPtr)tempPtr);
  1758.         argv[argc++] = (Ptr)tempPtr;
  1759.         lastvrefnum = vRefNum;
  1760.         GetNextMultiFile(&whichPane, &index, &vRefNum, fileName, FALSE);
  1761.         if (index >= 0 && argc > NUMARGVS - 1)
  1762.             { /* This is the only place where argv[] can overflow */
  1763.             NUMARGVS += 100; /* Apologies, NUMARGVS is actually a variable */
  1764.             newArgv = (char **)malloc(sizeof(char *) * NUMARGVS);
  1765.             if (newArgv == NULL)
  1766.                 return FALSE;
  1767.             BlockMove((Ptr)argv, (Ptr)newArgv, sizeof(char *) * (NUMARGVS - 100));
  1768.             free(argv);
  1769.             argv = newArgv;
  1770.             }
  1771.         }
  1772.     return(TRUE);
  1773.     }
  1774.  
  1775. /* Given "X:Y:...:File~22.c" use "X:Y:...:File~23.c"
  1776. --or if "X:Y:...:File.c" use "X:Y:...:File~1.c"
  1777. Keep incrementing version number until file does not exist.
  1778. Return NULL if resulting proper name would exceed 31 chars.
  1779. */
  1780. char *GetRenumberedName(char *oldName)
  1781.     {
  1782.     Ptr            copyOfName;
  1783.     long        len;
  1784.     short        refNum;
  1785.     short        counter = 0;
  1786.     OSErr        theErr = noErr;
  1787.     Boolean        nameExists = true;
  1788.     
  1789.     if (oldName == NULL)
  1790.         return NULL;
  1791.     
  1792.     len = strlen(oldName) + 6;
  1793.     copyOfName = NewPtr(len+1);
  1794.     if (!copyOfName)
  1795.         return(NULL);
  1796.     BlockMove(oldName, copyOfName, len+1);
  1797.     CtoPstr(copyOfName);
  1798.     do
  1799.         {
  1800.         if (!IncrementName((StringPtr)copyOfName))
  1801.             {
  1802.             counter = 1000;
  1803.             break;
  1804.             }
  1805.         theErr = FSOpen((StringPtr)copyOfName, 0, &refNum);
  1806.         if (theErr == noErr)
  1807.             FSClose(refNum);
  1808.         else
  1809.             nameExists = false;
  1810.         } while (nameExists && ++counter < 1000);
  1811.     
  1812.     if (counter >= 1000)
  1813.         {
  1814.         DisposePtr(copyOfName);
  1815.         copyOfName = NULL;
  1816.         }
  1817.     else
  1818.         PtoCstr((StringPtr)copyOfName);
  1819.     
  1820.     return(copyOfName);
  1821.     }
  1822.  
  1823. /* Locate and increment version number at end of name (set to ~1 if none present).
  1824. Returns false if resulting name would be too long.
  1825. */
  1826. Boolean IncrementName(StringPtr copyOfName)
  1827.     {
  1828.     StringPtr    startVNumber, endVNumber;
  1829.     StringPtr    properNameStart;
  1830.     Str31        versionNumberStr;
  1831.     long        versionNumber;
  1832.     short        oldNumberLength;
  1833.     short        newNumberLength;
  1834.     Boolean        haveVersionNumber = false;
  1835.     Boolean        result = true;
  1836.     
  1837.     endVNumber = ©OfName[copyOfName[0]];
  1838.     properNameStart = endVNumber;
  1839.     
  1840.     while ( properNameStart > copyOfName
  1841.             && *properNameStart != ':' )
  1842.         --properNameStart;
  1843.     ++properNameStart;
  1844.     
  1845.     while ( endVNumber > properNameStart
  1846.             && *endVNumber != '.' )
  1847.         --endVNumber;
  1848.     
  1849.     if (endVNumber > properNameStart)
  1850.         {
  1851.         startVNumber = endVNumber;
  1852.         while (startVNumber > properNameStart && num(*(startVNumber-1)) )
  1853.             --startVNumber;
  1854.         if ( startVNumber < endVNumber
  1855.           && startVNumber > properNameStart
  1856.           && *(startVNumber-1) == '~' )
  1857.             haveVersionNumber = true;
  1858.         }
  1859.     if (haveVersionNumber)
  1860.         {
  1861.         oldNumberLength = endVNumber - startVNumber;
  1862.         versionNumberStr[0] = oldNumberLength;
  1863.         BlockMove(startVNumber, versionNumberStr+1, versionNumberStr[0]);
  1864.         StringToNum(versionNumberStr, &versionNumber);
  1865.         ++versionNumber;
  1866.         NumToString(versionNumber, versionNumberStr);
  1867.         newNumberLength = versionNumberStr[0];
  1868.         
  1869.         if (newNumberLength > oldNumberLength) // new number is longer
  1870.             {
  1871.             short    extra;
  1872.             short    numToMove;
  1873.             // Make room for extra digits first
  1874.             extra = newNumberLength - oldNumberLength;
  1875.             numToMove = ©OfName[copyOfName[0]] + 1 - endVNumber;
  1876.             BlockMove(endVNumber, endVNumber + extra, numToMove);
  1877.             
  1878.             copyOfName[0] += extra;
  1879.             }
  1880.         // Move in the new number.
  1881.         BlockMove(versionNumberStr+1, startVNumber, newNumberLength);
  1882.         }
  1883.     else // no existing version number, make one up
  1884.         {
  1885.         short    extra;
  1886.         short    numToMove;
  1887.         
  1888.         versionNumberStr[0] = 2;
  1889.         versionNumberStr[1] = '~';
  1890.         versionNumberStr[2] = '1';
  1891.         
  1892.         extra = versionNumberStr[0];
  1893.         // Was there a trailing file extension?
  1894.         if (endVNumber <= properNameStart)
  1895.             {
  1896.             endVNumber = ©OfName[copyOfName[0]] + 1;
  1897.             }
  1898.         numToMove = ©OfName[copyOfName[0]] + 1 - endVNumber;
  1899.         if (numToMove > 0)
  1900.             BlockMove(endVNumber, endVNumber + extra, numToMove);
  1901.         copyOfName[0] += extra;
  1902.         // Move in the new number just created.
  1903.         BlockMove(versionNumberStr+1, endVNumber, versionNumberStr[0]);
  1904.         }
  1905.     
  1906.     // resulting name is unusable if it is too long
  1907.     if (©OfName[copyOfName[0]] + 1 - properNameStart > 31)
  1908.         result = false;
  1909.     return result;
  1910.     }
  1911.  
  1912. void RedrawItem(DialogPtr dPtr, short itemHit)
  1913.     {
  1914.     GrafPtr        savePort;
  1915.     short            kind;
  1916.     Handle        theHandle;
  1917.     MenuHandle    theMenu;
  1918.     Rect        box;
  1919.     
  1920.     GetPort(&savePort);
  1921.     SetPort (dPtr);
  1922.     GetDItem(dPtr, itemHit, &kind, &theHandle, &box);
  1923.     InvalRect(&box);
  1924.     SetPort(savePort);
  1925.     }
  1926.  
  1927. void RedrawDialog(DialogPtr dPtr)
  1928.     {
  1929.     GrafPtr        savePort;
  1930.     
  1931.     GetPort(&savePort);
  1932.     SetPort (dPtr);
  1933.     InvalRect(&dPtr->portRect);
  1934.     SetPort(savePort);
  1935.     }
  1936.  
  1937. /* Bail out if error during Indent run. */
  1938. void JumpOnIndentError(short inputErrorNumber)
  1939.     {
  1940.     
  1941.     gInputError = inputErrorNumber;
  1942.     longjmp(envBuf, 1); /* return to save point */
  1943.     }
  1944.  
  1945. void HandleIndentError()
  1946.     {
  1947.     /* -future- use gInputError */
  1948.     SysBeep(2);
  1949.     }
  1950.  
  1951.